/*
 * CDDL HEADER START
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://www.sun.com/cddl/cddl.html and legal/CDDLv1.0.txt
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
 * CDDL HEADER END
 * 
 * Portions Copyrighted 2009 Lumis EIP
 */
// This class is a copy of com.sun.portal.wsrp.producer.wsdl.WSDLServlet with some minor adjustments.

package lumis.service.wsrp.producer;

import com.sun.portal.wsrp.common.WSRPConfig;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Logger;
import com.sun.portal.wsrp.common.WSRPLogger;
import java.util.logging.Level;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lumis.portal.PortalContext;

import com.sun.portal.wsrp.producer.Producer;
import com.sun.portal.wsrp.producer.ProducerManager;
import com.sun.portal.wsrp.producer.ProducerVersion;
import com.sun.portal.wsrp.producer.ProducerException;
import com.sun.portal.wsrp.producer.ProducerManagerFactory;

/**
 * Delivers the producer's WSDL, according to its configurations.
 * 
 * @version $Revision: 11180 $ $Date: 2009-12-04 18:13:02 -0200 (Fri, 04 Dec 2009) $
 * @since 5.5.0
 */
@SuppressWarnings("serial")
public class ProducerWSDLServlet extends HttpServlet {

    private static final String CONTENT_TYPE_TEXT_XML = "text/xml";

    private static final int MARKUP_SERVICE_TYPE = 0;
    private static final int SERVICEDESCRIPTION_SERVICE_TYPE = 1;
    private static final int REGISTRATION_SERVICE_TYPE = 2;
    private static final int PORTLETMANAGEMENT_SERVICE_TYPE = 3;
    private static final int UNKNOWN_SERVICE_TYPE = 4;

    //private static final String PRODUCER_KEY = "producerKey";

    //private static final String BINDINGS_WSDL_RURL = "/wsrp/specifications/version2/";
    private static final String BINDINGS_WSDL_RURL = "/lumis/service/wsrp/producer/specifications/version2/";

    private static final String V1_BINDINGS_FILENAME = "wsrp_v1_bindings.wsdl";
    private static final String V2_BINDINGS_FILENAME = "wsrp-2.0-bindings.wsdl";

    private static final String V1_MARKUP_BINDING = "v1bind:WSRP_v1_Markup_Binding_SOAP";
    private static final String V1_MARKUP_NAME = "WSRP_v1_Markup_Service";
    private static final String V1_REGISTRATION_BINDING = "v1bind:WSRP_v1_Registration_Binding_SOAP";
    private static final String V1_REGISTRATION_NAME = "WSRP_v1_Registration_Service";
    private static final String V1_PORTLETMANAGEMENT_BINDING = "v1bind:WSRP_v1_PortletManagement_Binding_SOAP";
    private static final String V1_PORTLETMANAGEMENT_NAME = "WSRP_v1_PortletManagement_Service";
    private static final String V1_SERVICEDESCRIPTION_BINDING = "v1bind:WSRP_v1_ServiceDescription_Binding_SOAP";
    private static final String V1_SERVICEDESCRIPTION_NAME = "WSRP_v1_ServiceDescription_Service";



    private static final String V2_MARKUP_BINDING = "v2bind:WSRP_v2_Markup_Binding_SOAP";
    private static final String V2_MARKUP_NAME = "WSRP_v2_Markup_Service";
    private static final String V2_REGISTRATION_BINDING = "v2bind:WSRP_v2_Registration_Binding_SOAP";
    private static final String V2_REGISTRATION_NAME = "WSRP_v2_Registration_Service";
    private static final String V2_PORTLETMANAGEMENT_BINDING = "v2bind:WSRP_v2_PortletManagement_Binding_SOAP";
    private static final String V2_PORTLETMANAGEMENT_NAME = "WSRP_v2_PortletManagement_Service";
    private static final String V2_SERVICEDESCRIPTION_BINDING = "v2bind:WSRP_v2_ServiceDescription_Binding_SOAP";
    private static final String V2_SERVICEDESCRIPTION_NAME = "WSRP_v2_ServiceDescription_Service";


    //private static final String ROUTER_PREFIX = "/wsrp/router";
    private static final String ROUTER_PREFIX = "/lumis/service/wsrp/producer/router";

    private static final String V1_PREFIX = "/v1";
    private static final String V2_PREFIX = "/v2";

    private static final String MARKUP = "markup";
    private static final String REGISTRATION = "registration";
    private static final String SERVICEDESCRIPTION = "servicedescription";
    private static final String PORTLETMANAGEMENT = "portletmanagement";

    private static final String DEFAULT_PRODUCER_KEY = "default";

    private static List<String> SERVICES = null;
    private static Logger logger = WSRPLogger.getLogger(ProducerWSDLServlet.class,
            "logmessages");

    static {
        SERVICES = new ArrayList<String>();
        SERVICES.add(MARKUP);
        SERVICES.add(SERVICEDESCRIPTION);
        SERVICES.add(REGISTRATION);
        SERVICES.add(PORTLETMANAGEMENT);
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, java.io.IOException {
        res.setContentType(CONTENT_TYPE_TEXT_XML);

        String producerKey = getProducerKey(req);
        //String serverName = req.getServerName();
        //int serverPort = req.getServerPort();
        //String scheme = req.getScheme();
        //String contextPath = req.getContextPath();

        //String urlPrefix = scheme + "://" + serverName + ":" + serverPort + contextPath;
        String urlPrefix = PortalContext.getFrameworkUrl();

        String bindingsURL = urlPrefix + BINDINGS_WSDL_RURL;

        if (producerKey == null || producerKey.length() == 0) {
            res.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
        } else {
            Producer producer = null;

            try {
                ProducerManager producerManager = ProducerManagerFactory.
                        getProducerManager(getPortalId());
                producer = producerManager.getProducer(producerKey);

                if(producer==null){
                    throw new ProducerException("Unable to obtain producer with key : " + producerKey);
                }

                PrintWriter writer = res.getWriter();
                writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

                writeNamespaceHeader(producer, writer); 
                writeBindingWSDLImports(bindingsURL, producer, writer);
                //Write WSRP V1 Service
                writeWSRPV1Service(req, res, producer, writer);
                //Write WSRP v2 Service
                writeWSRPV2Service(req, res, producer, writer);

                writer.println("</wsdl:definitions>");

            } catch (ProducerException pe) {
                res.setStatus(HttpServletResponse.SC_NOT_FOUND);
                logger.log(Level.SEVERE, "PSWS_CSPWPW0001", pe);
                return;
            }
            
        }
    }

    private int getServiceType(String s) {
        int serviceType;

        if (s == null) {
            serviceType = UNKNOWN_SERVICE_TYPE;
        } else if (s.equalsIgnoreCase(MARKUP)) {
            serviceType = MARKUP_SERVICE_TYPE;
        } else if (s.equalsIgnoreCase(SERVICEDESCRIPTION)) {
            serviceType = SERVICEDESCRIPTION_SERVICE_TYPE;
        } else if (s.equalsIgnoreCase(REGISTRATION)) {
            serviceType = REGISTRATION_SERVICE_TYPE;
        } else if (s.equalsIgnoreCase(PORTLETMANAGEMENT)) {
            serviceType = PORTLETMANAGEMENT_SERVICE_TYPE;
        } else {
            serviceType = UNKNOWN_SERVICE_TYPE;
        }

        return serviceType;
    }

    private String getProducerKey(HttpServletRequest req) throws ServletException {
        String pathinfo = req.getPathInfo();
        String producerKey = null;

        if (pathinfo == null) {
            producerKey = DEFAULT_PRODUCER_KEY;
        } else {
            producerKey = pathinfo.substring(1);
        }

        return producerKey;
    }

    private String getPortalId() {
        return WSRPConfig.getPortalId();
    }
    
    private void writeNamespaceHeader(Producer producer, PrintWriter writer) 
        throws ProducerException{

        writer.println("<wsdl:definitions targetNamespace=\"urn:oasis:names:tc:wsrp:v2:wsdl\" ");
        if(!producer.getVersion().equals(ProducerVersion.VERSION1)){        
            writer.print("xmlns:v2bind=\"urn:oasis:names:tc:wsrp:v2:bind\" ");        
        }
        if(!producer.getVersion().equals(ProducerVersion.VERSION2)){        
            writer.print("xmlns:v1bind=\"urn:oasis:names:tc:wsrp:v1:bind\" ");
        }
        writer.print("xmlns=\"http://schemas.xmlsoap.org/wsdl/\" ");
        writer.print("xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\" ");
        writer.print("xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\">");
        
    }
    private void writeBindingWSDLImports(String bindingsURL, Producer producer, 
            PrintWriter writer) throws ProducerException{
        String v2_prefixStr = "<import namespace=\"urn:oasis:names:tc:wsrp:v2:bind\" location=\"";
        if(!producer.getVersion().equals(ProducerVersion.VERSION1)){
            writer.println(v2_prefixStr + bindingsURL + V2_BINDINGS_FILENAME + "\"/>");
        }
        String v1_prefixStr = "<import namespace=\"urn:oasis:names:tc:wsrp:v1:bind\" location=\"";
        if(!producer.getVersion().equals(ProducerVersion.VERSION2)){
            writer.println(v1_prefixStr + bindingsURL + V1_BINDINGS_FILENAME + "\"/>");
        }
        
    }

    private void writeWSRPV1Service(HttpServletRequest req, HttpServletResponse res,
            Producer producer,
            PrintWriter writer) throws IOException, ProducerException{

        //Check the producer wsdl version. If it is V2, return w/o adding anything
        if(producer.getVersion().equals(ProducerVersion.VERSION2)){
            return;
        }
        
        //String serverName = req.getServerName();
        //int serverPort = req.getServerPort();
        //String scheme = req.getScheme();
        //String contextPath = req.getContextPath();
        String producerKey = producer.getProducerKey();
        //String urlPrefix = scheme + "://" + serverName + ":" + serverPort + contextPath;
        String urlPrefix = PortalContext.getFrameworkUrl();

        //String bindingsURL = urlPrefix + BINDINGS_WSDL_RURL;

        writer.println("<wsdl:service name=\"WSRP_v1_Service\">");

        String location = null;
        String name = null;
        String binding = null;

        for (Iterator<String> i = SERVICES.iterator(); i.hasNext(); ) {
            int serviceType = getServiceType((String)i.next());

            switch (serviceType) {
                case MARKUP_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX + V1_PREFIX + "/" + MARKUP + "/" + producerKey;
                    name = V1_MARKUP_NAME;
                    binding = V1_MARKUP_BINDING;

                    break;

                case SERVICEDESCRIPTION_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX  + V1_PREFIX + "/" + SERVICEDESCRIPTION + "/" + producerKey;
                    name = V1_SERVICEDESCRIPTION_NAME;
                    binding = V1_SERVICEDESCRIPTION_BINDING;

                    break;

                case PORTLETMANAGEMENT_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX + V1_PREFIX + "/" + PORTLETMANAGEMENT + "/" + producerKey;
                    name = V1_PORTLETMANAGEMENT_NAME;
                    binding = V1_PORTLETMANAGEMENT_BINDING;

                    break;

                case REGISTRATION_SERVICE_TYPE:
                    //
                    // if registration is not required, or if
                    // in-band registration is not supported,
                    // do not expose the registration port type
                    //
                    try{
                        if (!producer.requiresRegistration()) {
                            continue;
                        }
                        if (!producer.inbandRegistrationSupported()) {
                            continue;
                        }
                    } catch (ProducerException pe) {
                        res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        logger.log(Level.SEVERE, "PSWS_CSPWPW0001", pe);
                        return;
                    }

                    // expose port type

                    location = urlPrefix + ROUTER_PREFIX + V1_PREFIX + "/" + REGISTRATION + "/" + producerKey;
                    name = V1_REGISTRATION_NAME;
                    binding = V1_REGISTRATION_BINDING;

                    break;
            }

            writer.println("<wsdl:port binding=\"" + binding + "\" name=\"" + name + "\">");
            writer.println("<soap:address location=\"" + location + "\"/>");
            writer.println("</wsdl:port>");
        }

        writer.println("</wsdl:service>");
    }

    private void writeWSRPV2Service(HttpServletRequest req, HttpServletResponse res,
            Producer producer,
            PrintWriter writer) throws IOException, ProducerException{
            
        //Check the producer wsdl version. If it is V1, return w/o adding anything
        if(producer.getVersion().equals(ProducerVersion.VERSION1)){
            return;
        }
        //String serverName = req.getServerName();
        //int serverPort = req.getServerPort();
        //String scheme = req.getScheme();
        //String contextPath = req.getContextPath();
        String producerKey = producer.getProducerKey();
        //String urlPrefix = scheme + "://" + serverName + ":" + serverPort + contextPath;
        String urlPrefix = PortalContext.getFrameworkUrl();

        //String bindingsURL = urlPrefix + BINDINGS_WSDL_RURL;

        writer.println("<wsdl:service name=\"WSRP_v2_Service\">");

        String location = null;
        String name = null;
        String binding = null;

        for (Iterator<String> i = SERVICES.iterator(); i.hasNext(); ) {
            int serviceType = getServiceType((String)i.next());

            switch (serviceType) {
                case MARKUP_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX + V2_PREFIX + "/" + MARKUP + "/" + producerKey;
                    name = V2_MARKUP_NAME;
                    binding = V2_MARKUP_BINDING;

                    break;

                case SERVICEDESCRIPTION_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX + V2_PREFIX + "/" + SERVICEDESCRIPTION + "/" + producerKey;
                    name = V2_SERVICEDESCRIPTION_NAME;
                    binding = V2_SERVICEDESCRIPTION_BINDING;

                    break;

                case PORTLETMANAGEMENT_SERVICE_TYPE:
                    location = urlPrefix + ROUTER_PREFIX + V2_PREFIX + "/" + PORTLETMANAGEMENT + "/" + producerKey;
                    name = V2_PORTLETMANAGEMENT_NAME;
                    binding = V2_PORTLETMANAGEMENT_BINDING;

                    break;

                case REGISTRATION_SERVICE_TYPE:
                    //
                    // if registration is not required, or if
                    // in-band registration is not supported,
                    // do not expose the registration port type
                    //
                    try{
                        if (!producer.requiresRegistration()) {
                            continue;
                        }
                        if (!producer.inbandRegistrationSupported()) {
                            continue;
                        }
                    } catch (ProducerException pe) {
                        res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                        logger.log(Level.SEVERE, "PSWS_CSPWPW0001", pe);
                        return;
                    }

                    // expose port type

                    location = urlPrefix + ROUTER_PREFIX + V2_PREFIX + "/" + REGISTRATION + "/" + producerKey;
                    name = V2_REGISTRATION_NAME;
                    binding = V2_REGISTRATION_BINDING;

                    break;
            }

            writer.println("<wsdl:port binding=\"" + binding + "\" name=\"" + name + "\">");
            writer.println("<soap:address location=\"" + location + "\"/>");
            writer.println("</wsdl:port>");
        }

        writer.println("</wsdl:service>");
    }
}
